package com.yaorange.nongjt.service.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

import com.yaorange.common.config.RuoYiConfig;
import com.yaorange.common.exception.ServiceException;
import com.yaorange.common.utils.DateUtils;
import com.yaorange.common.utils.PageUtils;
import com.yaorange.common.utils.uuid.UUID;
import com.yaorange.nongjt.vo.NjtCertificateVo;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import com.yaorange.nongjt.mapper.NjtCertificateMapper;
import com.yaorange.nongjt.domain.NjtCertificate;
import com.yaorange.nongjt.service.INjtCertificateService;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;

/**
 * 合格证打印数据Service业务层处理
 * 
 * @author juheng
 * @date 2025-02-28
 */
@Service
public class NjtCertificateServiceImpl implements INjtCertificateService 
{
    private static final Logger log = LoggerFactory.getLogger(NjtCertificateServiceImpl.class);

    @Autowired
    private NjtCertificateMapper njtCertificateMapper;

    @Autowired
    private  NjtCommonService commonService;

    /**
     * 查询合格证打印数据
     * 
     * @param id 合格证打印数据主键
     * @return 合格证打印数据
     */
    @Override
    public NjtCertificateVo selectNjtCertificateById(Long id)
    {
        return njtCertificateMapper.selectNjtCertificateById(id);
    }

    /**
     * 查询合格证打印数据列表
     *
     * @param njtCertificate 合格证打印数据
     * @return 合格证打印数据
     */
    @Override
    @Transactional(readOnly = true)
    public List<NjtCertificateVo> selectNjtCertificateList(NjtCertificateVo njtCertificate)
    {
        return njtCertificateMapper.selectNjtCertificateList(njtCertificate);
    }

    /**
     * 新增合格证打印数据
     * 
     * @param njtCertificate 合格证打印数据
     * @return 结果
     */
    @Override
    public int insertNjtCertificate(NjtCertificate njtCertificate)
    {
        njtCertificate.setCreateTime(DateUtils.getNowDate());
        return njtCertificateMapper.insertNjtCertificate(njtCertificate);
    }

    /**
     * 修改合格证打印数据
     * 
     * @param njtCertificate 合格证打印数据
     * @return 结果
     */
    @Override
    public int updateNjtCertificate(NjtCertificate njtCertificate)
    {
        njtCertificate.setUpdateTime(DateUtils.getNowDate());
        return njtCertificateMapper.updateNjtCertificate(njtCertificate);
    }

    /**
     * 批量删除合格证打印数据
     * 
     * @param ids 需要删除的合格证打印数据主键
     * @return 结果
     */
    @Override
    public int deleteNjtCertificateByIds(Long[] ids)
    {
        return njtCertificateMapper.deleteNjtCertificateByIds(ids);
    }

    /**
     * 删除合格证打印数据信息
     * 
     * @param id 合格证打印数据主键
     * @return 结果
     */
    @Override
    public int deleteNjtCertificateById(Long id)
    {
        return njtCertificateMapper.deleteNjtCertificateById(id);
    }

    //创建单线程池
    private static final ExecutorService executor = Executors.newSingleThreadExecutor();
    //当前导出进度
    private volatile int progress = 0;
    //定义信号量（这里使用信号量是因为锁只能在开启的线程内解锁，但是信号量可以跨线程）
    private final Semaphore semaphore = new Semaphore(1);

    /**
     * 异步导出
     * @return
     */
    @Override
    public String exportAll() {
        // 尝试获取一个信号量，如果获取不到，说明当前正有线程正在导出，直接抛出异常
        if (!semaphore.tryAcquire()) {
            throw new ServiceException("当前有其他管理员在导出，请稍后重试");
        }

        //这里进度要改成0，否则导出时，有可能直接查到100，然后导致下载但没有数据
        progress = 0;

        //随机生成文件名
        String filename = UUID.randomUUID() + ".xlsx";
        //异步指定excel导出，并保存到本地临时文件
        executor.execute(()->{
            //从第一页开始
            Integer pageNum = 1;
            //每页1000条
            Integer pageSize = 1000;

            //保存的路径
            String parentFilePath = RuoYiConfig.getProfile();
            //判断目录是否存在
            File file = new File(parentFilePath);
            //如果文件夹不存在，则创建文件夹
            if(!file.exists()){
                file.mkdirs();
            }
            //拼接文件名

            String outputPath = parentFilePath + "/" + filename;
            //读取模板
            ClassPathResource classPathResource = new ClassPathResource("excel/certificate_print_template.xlsx");
            XSSFWorkbook wb;
            try {
                //创建XSSFWordBook（操作office的类）
                wb = new XSSFWorkbook(classPathResource.getInputStream());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            //获取第一个表
            XSSFSheet sheet = wb.getSheetAt(0);

            //当前读到多少条（1000条一组）
            int size = 0;
            //统计当前查询的总数
            int total = 0;

            int count = njtCertificateMapper.selectAllCount();
            do {
                //分页助手
                PageUtils.startPage(pageNum++, pageSize);
                //查询list
                List<NjtCertificateVo> njtCertificateVos = njtCertificateMapper.selectNjtCertificateList(null);
                //记录这次查询有多少条
                size = njtCertificateVos.size();
                total += size;
                //计算当前进度
                progress = total * 100 / count;

                //循环遍历，将数据写入
                for (NjtCertificateVo njtCertificateVo : njtCertificateVos) {
                    int lastRowNum = sheet.getLastRowNum();
                    XSSFRow row = sheet.createRow(lastRowNum + 1);
                    int xb = 0;
                    row.createCell(xb++).setCellValue(njtCertificateVo.getUserId());
                    row.createCell(xb++).setCellValue(njtCertificateVo.getProductName());
                    row.createCell(xb++).setCellValue(njtCertificateVo.getProductWeight().toString());
                    row.createCell(xb++).setCellValue(njtCertificateVo.getUnit());
                    row.createCell(xb++).setCellValue(njtCertificateVo.getProduceAddress());
                    row.createCell(xb++).setCellValue(njtCertificateVo.getTestType());
                    row.createCell(xb++).setCellValue(njtCertificateVo.getPrintNumber());
                    row.createCell(xb++).setCellValue(njtCertificateVo.getScanNum());
                }
                try (FileOutputStream fileOutputStream = new FileOutputStream(outputPath)){
                    //获得文件的输出流

                    //将数据写入文件中
                    wb.write(fileOutputStream);
                    //写入，关闭资源
                    fileOutputStream.flush();
                    fileOutputStream.close();
                } catch (Exception e) {
                    log.error(e.getMessage());
                }
                //如果size 不是1000就停止运行，因为这里前端无法等待太久，所有改成了只查询5次
            }while (size == pageSize);

            try {
                //关闭资源
                wb.close();
            } catch (IOException e) {
                log.error(e.getMessage());
            }

            //保存完后，将信号量释放
            semaphore.release();
        });
        return filename;
    }

    /**
     * 返回当前的导出进度
     * @return
     */
    @Override
    public Integer progress() {
        return progress;
    }

    /**
     * 导出到本地临时文件后，客户端调用接口下载文件
     * @param response
     * @param tempFile
     */
    @Override
    public void download(HttpServletResponse response, String tempFile) {
        String outputPath = RuoYiConfig.getProfile() + "/" + tempFile;
        //声明响应的类型
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        try(FileInputStream fileInputStream = new FileInputStream(outputPath)){
            //读取文件，并写入到响应体中

            byte[] bytes = new byte[1024];
            int read = 0;
            while((read = fileInputStream.read(bytes)) != -1){
                response.getOutputStream().write(bytes, 0, read);
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }

        //下载完后删除临时文件
        new File(outputPath).delete();
    }

    /***
     * 数据导出
     * @param response
     * @param njtCertificate
     */
    @Override
    public void exportAll(HttpServletResponse response, NjtCertificateVo njtCertificate) {
        //从第一页开始
        Integer pageNum = 1;
        //每页1000条
        Integer pageSize = 1000;

        //保存的路径
        String parentFilePath = "D:\\ruoyi\\uploadPath\\excel\\";
        //判断目录是否存在
        File file = new File(parentFilePath);
        //如果文件夹不存在，则创建文件夹
        if(!file.exists()){
            file.mkdirs();
        }
        //拼接文件名
        String outputPath = parentFilePath + UUID.randomUUID() + ".xlsx";
        //读取模板
        ClassPathResource classPathResource = new ClassPathResource("excel/certificate_print_template.xlsx");
        XSSFWorkbook wb;
        try {
            //创建XSSFWordBook（操作office的类）
            wb = new XSSFWorkbook(classPathResource.getInputStream());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        //获取第一个表
        XSSFSheet sheet = wb.getSheetAt(0);

        //当前读到多少条（1000条一组）
        int size = 0;

        //判断当前用户角色，根据不同的角色加上不同的条件
        commonService.getAuthNjtCertificate(njtCertificate);
        do {

            //分页助手
            PageUtils.startPage(pageNum++, pageSize);
            //查询list
            List<NjtCertificateVo> njtCertificateVos = njtCertificateMapper.selectNjtCertificateList(njtCertificate);
            //记录这次查询有多少条
            size = njtCertificateVos.size();

            //循环遍历，将数据写入
            for (NjtCertificateVo njtCertificateVo : njtCertificateVos) {
                int lastRowNum = sheet.getLastRowNum();
                XSSFRow row = sheet.createRow(lastRowNum + 1);
                int xb = 0;
                row.createCell(xb++).setCellValue(njtCertificateVo.getUserId());
                row.createCell(xb++).setCellValue(njtCertificateVo.getProductName());
                row.createCell(xb++).setCellValue(njtCertificateVo.getProductWeight().toString());
                row.createCell(xb++).setCellValue(njtCertificateVo.getUnit());
                row.createCell(xb++).setCellValue(njtCertificateVo.getProduceAddress());
                row.createCell(xb++).setCellValue(njtCertificateVo.getTestType());
                row.createCell(xb++).setCellValue(njtCertificateVo.getPrintNumber());
                row.createCell(xb++).setCellValue(njtCertificateVo.getScanNum());
            }
            try (FileOutputStream fileOutputStream = new FileOutputStream(outputPath)){
                //获得文件的输出流

                //将数据写入文件中
                wb.write(fileOutputStream);
                //写入，关闭资源
                fileOutputStream.flush();
                fileOutputStream.close();
            } catch (Exception e) {
                log.error(e.getMessage());
            }
            //如果size 不是1000就停止运行，因为这里前端无法等待太久，所有改成了只查询5次
        }while (size == pageSize);

        try {
            //关闭资源
            wb.close();
        } catch (IOException e) {
            log.error(e.getMessage());
        }

        //声明响应的类型
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        try(FileInputStream fileInputStream = new FileInputStream(outputPath)){
            //读取文件，并写入到响应体中

            byte[] bytes = new byte[1024];
            int read = 0;
            while((read = fileInputStream.read(bytes)) != -1){
                response.getOutputStream().write(bytes, 0, read);
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }

        new File(outputPath).delete();
    }
}
